home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / minix / up1510b.tgz / up1510b / src / fs / path.c < prev    next >
C/C++ Source or Header  |  1990-07-23  |  12KB  |  348 lines

  1. /* This file contains the procedures that look up path names in the directory
  2.  * system and determine the inode number that goes with a given path name.
  3.  *
  4.  *  The entry points into this file are
  5.  *   eat_path:     the 'main' routine of the path-to-inode conversion mechanism
  6.  *   last_dir:     find the final directory on a given path
  7.  *   advance:     parse one component of a path name
  8.  *   search_dir: search a directory for a string and return its inode number
  9.  */
  10.  
  11. #include "fs.h"
  12. #include <string.h>
  13. #include <minix/callnr.h>
  14. #include "buf.h"
  15. #include "file.h"
  16. #include "fproc.h"
  17. #include "inode.h"
  18. #include "super.h"
  19.  
  20. FORWARD char *get_name();
  21.  
  22. /*===========================================================================*
  23.  *                eat_path                     *
  24.  *===========================================================================*/
  25. PUBLIC struct inode *eat_path(path)
  26. char *path;            /* the path name to be parsed */
  27. {
  28. /* Parse the path 'path' and put its inode in the inode table. If not possible,
  29.  * return NIL_INODE as function value and an error code in 'err_code'.
  30.  */
  31.  
  32.   register struct inode *ldip, *rip;
  33.   char string[NAME_MAX];    /* hold 1 path component name here */
  34.  
  35.   /* First open the path down to the final directory. */
  36.   if ( (ldip = last_dir(path, string)) == NIL_INODE)
  37.     return(NIL_INODE);    /* we couldn't open final directory */
  38.  
  39.   /* The path consisting only of "/" is a special case, check for it. */
  40.   if (string[0] == '\0') return(ldip);
  41.  
  42.   /* Get final component of the path. */
  43.   rip = advance(ldip, string);
  44.   put_inode(ldip);
  45.   return(rip);
  46. }
  47.  
  48.  
  49. /*===========================================================================*
  50.  *                last_dir                     *
  51.  *===========================================================================*/
  52. PUBLIC struct inode *last_dir(path, string)
  53. char *path;            /* the path name to be parsed */
  54. char string[NAME_MAX];        /* the final component is returned here */
  55. {
  56. /* Given a path, 'path', located in the fs address space, parse it as
  57.  * far as the last directory, fetch the inode for the last directory into
  58.  * the inode table, and return a pointer to the inode.  In
  59.  * addition, return the final component of the path in 'string'.
  60.  * If the last directory can't be opened, return NIL_INODE and
  61.  * the reason for failure in 'err_code'.
  62.  */
  63.  
  64.   register struct inode *rip;
  65.   register char *new_name;
  66.   register struct inode *new_ip;
  67.   char *p;
  68.  
  69.   /* Is the path absolute or relative?  Initialize 'rip' accordingly. */
  70.   rip = (*path == '/' ? fp->fp_rootdir : fp->fp_workdir);
  71.  
  72.   /* If dir has been removed or path is empty, return ENOENT. */
  73.   if (rip->i_nlinks == 0 || *path == '\0') {
  74.     err_code = ENOENT;
  75.     return(NIL_INODE);
  76.   }
  77.  
  78.   dup_inode(rip);        /* inode will be returned with put_inode */
  79.  
  80.   /* Remove trailing "/." from paths (e.g., "/usr/ast/." becomes "/usr/ast") */
  81.   if (fs_call == UNLINK || fs_call == RMDIR) {
  82.     while (1) {
  83.         p = path + strlen(path) - 2;    /* pts to next-to-last char */
  84.         if (p > path && *p == '/' && *(p + 1) == '.') 
  85.             *p = '\0';
  86.         else
  87.             break;
  88.     }
  89.   }
  90.  
  91.   /* Scan the path component by component. */
  92.   while (TRUE) {
  93.     /* Extract one component. */
  94.     if ( (new_name = get_name(path, string)) == (char*) 0) {
  95.         put_inode(rip);    /* bad path in user space */
  96.         return(NIL_INODE);
  97.     }
  98.     if (*new_name == '\0') return(rip);    /* normal exit */
  99.  
  100.     /* There is more path.  Keep parsing. */
  101.     new_ip = advance(rip, string);
  102.     put_inode(rip);        /* rip either obsolete or irrelevant */
  103.     if (new_ip == NIL_INODE) return(NIL_INODE);
  104.  
  105.     /* The call to advance() succeeded.  Fetch next component. */
  106.     path = new_name;
  107.     rip = new_ip;
  108.   }
  109. }
  110.  
  111.  
  112. /*===========================================================================*
  113.  *                get_name                     *
  114.  *===========================================================================*/
  115. PRIVATE char *get_name(old_name, string)
  116. char *old_name;            /* path name to parse */
  117. char string[NAME_MAX];        /* component extracted from 'old_name' */
  118. {
  119. /* Given a pointer to a path name in fs space, 'old_name', copy the next
  120.  * component to 'string' and pad with zeros.  A pointer to that part of
  121.  * the name as yet unparsed is returned.  Roughly speaking,
  122.  * 'get_name' = 'old_name' - 'string'.
  123.  *
  124.  * This routine follows the standard convention that /usr/ast, /usr//ast,
  125.  * //usr///ast and /usr/ast/ are all equivalent.
  126.  */
  127.  
  128.   register int c;
  129.   register char *np, *rnp;
  130.  
  131.   np = string;            /* 'np' points to current position */
  132.   rnp = old_name;        /* 'rnp' points to unparsed string */
  133.   while ( (c = *rnp) == '/') rnp++;    /* skip leading slashes */
  134.  
  135.   /* Copy the unparsed path, 'old_name', to the array, 'string'. */
  136.   while ( rnp < &old_name[PATH_MAX]  &&  c != '/'   &&  c != '\0') {
  137.     if (np < &string[NAME_MAX]) *np++ = c;
  138.     c = *++rnp;        /* advance to next character */
  139.   }
  140.  
  141.   /* To make /usr/ast/ equivalent to /usr/ast, skip trailing slashes. */
  142.   while (c == '/' && rnp < &old_name[PATH_MAX]) c = *++rnp;
  143.  
  144.   /* Pad the component name out to NAME_MAX chars, using 0 as filler. */
  145.   while (np < &string[NAME_MAX]) *np++ = '\0';
  146.  
  147.   if (rnp >= &old_name[PATH_MAX]) {
  148.     err_code = ENAMETOOLONG;
  149.     return((char *) 0);
  150.   }
  151.   return(rnp);
  152. }
  153.  
  154.  
  155. /*===========================================================================*
  156.  *                advance                         *
  157.  *===========================================================================*/
  158. PUBLIC struct inode *advance(dirp, string)
  159. struct inode *dirp;        /* inode for directory to be searched */
  160. char string[NAME_MAX];        /* component name to look for */
  161. {
  162. /* Given a directory and a component of a path, look up the component in
  163.  * the directory, find the inode, open it, and return a pointer to its inode
  164.  * slot.  If it can't be done, return NIL_INODE.
  165.  */
  166.  
  167.   register struct inode *rip;
  168.   struct inode *rip2;
  169.   register struct super_block *sp;
  170.   int r;
  171.   dev_t mnt_dev;
  172.   ino_t numb;
  173.  
  174.   /* If 'string' is empty, yield same inode straight away. */
  175.   if (string[0] == '\0') return(get_inode(dirp->i_dev, dirp->i_num));
  176.  
  177.   /* Check for NIL_INODE. */
  178.   if (dirp == NIL_INODE) return(NIL_INODE);
  179.  
  180.   /* If 'string' is not present in the directory, signal error. */
  181.   if ( (r = search_dir(dirp, string, &numb, LOOK_UP)) != OK) {
  182.     err_code = r;
  183.     return(NIL_INODE);
  184.   }
  185.  
  186.   /* The component has been found in the directory.  Get inode. */
  187.   if ( (rip = get_inode(dirp->i_dev, numb)) == NIL_INODE) return(NIL_INODE);
  188.  
  189.   if (rip->i_num == ROOT_INODE)
  190.     if (dirp->i_num == ROOT_INODE) {
  191.         if (string[1] == '.') {
  192.         for (sp = &super_block[1]; sp < &super_block[NR_SUPERS]; sp++){
  193.             if (sp->s_dev == rip->i_dev) {
  194.                 /* Release the root inode.  Replace by the
  195.                  * inode mounted on.
  196.                  */
  197.                 put_inode(rip);
  198.                 mnt_dev = sp->s_imount->i_dev;
  199.                 rip2 = get_inode(mnt_dev, sp->s_imount->i_num);
  200.                 rip = advance(rip2, string);
  201.                 put_inode(rip2);
  202.                 break;
  203.             }
  204.         }
  205.         }
  206.     }
  207.   if (rip == NIL_INODE) return(NIL_INODE);
  208.  
  209.   /* See if the inode is mounted on.  If so, switch to root directory of the
  210.    * mounted file system.  The super_block provides the linkage between the
  211.    * inode mounted on and the root directory of the mounted file system.
  212.    */
  213.   while (rip != NIL_INODE && rip->i_mount == I_MOUNT) {
  214.     /* The inode is indeed mounted on. */
  215.     for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++) {
  216.         if (sp->s_imount == rip) {
  217.             /* Release the inode mounted on.  Replace by the
  218.              * inode of the root inode of the mounted device.
  219.              */
  220.             put_inode(rip);
  221.             rip = get_inode(sp->s_dev, ROOT_INODE);
  222.             break;
  223.         }
  224.     }
  225.   }
  226.   return(rip);        /* return pointer to inode's component */
  227. }
  228.  
  229.  
  230. /*===========================================================================*
  231.  *                search_dir                     *
  232.  *===========================================================================*/
  233. PUBLIC int search_dir(ldir_ptr, string, numb, flag)
  234. register struct inode *ldir_ptr;    /* ptr to inode for dir to search */
  235. char string[NAME_MAX];        /* component to search for */
  236. ino_t *numb;            /* pointer to inode number */
  237. int flag;            /* LOOK_UP, ENTER, or DELETE */
  238. {
  239. /* This function searches the directory whose inode is pointed to by 'ldip':
  240.  * if (flag == ENTER)  enter 'string' in the directory with inode # '*numb';
  241.  * if (flag == DELETE) delete 'string' from the directory;
  242.  * if (flag == LOOK_UP) se